import type { PageType } from '../../../lib/page_handler/type'
import type { ComponentStyleIdType, PlatformTypeValue } from '../../../types/interfaces'
import { BaseModule } from '../../../lib/abstract'
import { PageHandler } from '../../../lib/page_handler'
import {
  BIAN_PAGINATION_CONFIG,
  BianPageType,
} from '../../../lib/page_handler/platform/bian/types'
import {
  GITEE_PAGINATION_CONFIG,
  GiteePageType,
} from '../../../lib/page_handler/platform/gitee/types'
import {
  GITHUB_PAGE_PAGINATION_CONFIG,
  GithubPageType,
} from '../../../lib/page_handler/platform/github/types'
import {
  GREASY_FORK_PAGINATION_CONFIG,
  GreasyForkPageType,
} from '../../../lib/page_handler/platform/greasyfork/types'
import { SogouPageType } from '../../../lib/page_handler/platform/sogou/types'
import { ToolKit } from '../../../lib/utils/toolkit'
import {
  ComponentStyleId,
  HOSTNAME,
  logger,
  SUPPORTED_PLATFORMS,
} from '../../../types/constants'
import { ConfigManager } from '../../config_manager'

interface KeyboardPaginationConfig {
  container: string
  itemSelector: string
  selectedSelector: string
}
type KeyboardPaginationPlatformConfig = Partial<Record<PlatformTypeValue, Record<string, KeyboardPaginationConfig>>>

interface Config {
  enabled?: boolean
}

// 测试链接：https://pic.netbian.com/new/
export class KeyboardPagination extends BaseModule {
  readonly id: string = 'keyboard_pagination'
  readonly styleId: string = ComponentStyleId[this.name]
  isInitialized: boolean = false
  readonly supportedPlatforms: string[] = ConfigManager.getInstance().moduleSupportedPlatforms(this.name)
  private static instance: KeyboardPagination
  private readonly documentKeyEventName = 'keydown.keyboard-pagination'
  private readonly currentPageType: PageType = PageHandler.getCurrentPageType()

  config: Config = {
    enabled: true,
  }

  get name(): ComponentStyleIdType {
    return 'KeyboardPagination'
  }

  handleCleanupOthers(): void {
    $(document).off(this.documentKeyEventName)
  }

  /**
   * 获取单例实例
   */
  public static getInstance(): KeyboardPagination {
    if (!KeyboardPagination.instance) {
      KeyboardPagination.instance = new KeyboardPagination()
    }
    return KeyboardPagination.instance
  }

  core(): void {
    this.loadConfig()

    if (!this.config.enabled)
      return

    this.handlePagination()
  }

  onToggleCallback(_id: string, checked: boolean): void {
    super.onToggleCallback(_id, checked)
  }

  handlePagination(): void {
    const SO_GOU_DEFAULT_CONFIG = {
      container: '#sogou_wrap_id #pagebar_container',
      itemSelector: 'a, span',
      selectedSelector: 'span',
    }

    const config: KeyboardPaginationPlatformConfig = {
      [SUPPORTED_PLATFORMS.BIAN]: {
        [BianPageType.List]: {
          container: BIAN_PAGINATION_CONFIG.selector.container,
          itemSelector: BIAN_PAGINATION_CONFIG.childSelector.allPage,
          selectedSelector: BIAN_PAGINATION_CONFIG.childSelector.currentPage,
        },
      },
      [SUPPORTED_PLATFORMS.SO_GOU]: {
        [SogouPageType.Web]: SO_GOU_DEFAULT_CONFIG,
        [SogouPageType.Weixin]: {
          ...SO_GOU_DEFAULT_CONFIG,
          container: '#wrapper #pagebar_container',
        },
        [SogouPageType.Zhihu]: SO_GOU_DEFAULT_CONFIG,
        [SogouPageType.Video]: {
          container: '#container .play_list_pg',
          itemSelector: 'a',
          selectedSelector: 'a.on',
        },
        [SogouPageType.Medical]: SO_GOU_DEFAULT_CONFIG,
        [SogouPageType.Ask]: SO_GOU_DEFAULT_CONFIG,
        [SogouPageType.Encyclopedia]: SO_GOU_DEFAULT_CONFIG,
        [SogouPageType.News]: SO_GOU_DEFAULT_CONFIG,
        [SogouPageType.Knowledge]: SO_GOU_DEFAULT_CONFIG,
      },
      [SUPPORTED_PLATFORMS.GREASY_FORK]: {
        [GreasyForkPageType.SCRIPT_LIST]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.SCRIPT_VERSIONS]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.SCRIPT_FEEDBACK]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.DISCUSSIONS]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.DISCUSSIONS_GREASY_FORK]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.DISCUSSIONS_DEVELOPMENT]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.DISCUSSIONS_SCRIPT]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.DISCUSSIONS_NO_SCRIPT]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.USERS]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.MODERATOR_ACTIONS]: this.getGreasyForkKeyConfig(),
        [GreasyForkPageType.LIBRARIES]: this.getGreasyForkKeyConfig(),
      },
      [SUPPORTED_PLATFORMS.GITEE]: {
        [GiteePageType.Commits]: this.getGiteeKeyConfig(),
      },
      [SUPPORTED_PLATFORMS.GITHUB]: {
        [GithubPageType.Commits]: this.getGithubKeyConfig(),
        [GithubPageType.Tags]: this.getGithubKeyConfig(),
      },
    }

    const currentConfig = config[HOSTNAME]?.[this.currentPageType]

    if (!currentConfig) {
      logger.warn(`[${this.name}] 未找到当前页面类型的配置，跳过处理`)
      return
    }

    $(document).on(this.documentKeyEventName, (e) => {
      // 检查是否在输入框中，避免冲突
      if ($(e.target).is('input, textarea, select')) {
        return
      }

      switch (e.key) {
        case 'ArrowLeft':
          e.preventDefault()
          this.navigateToPreviousPage(currentConfig)
          break

        case 'ArrowRight':
          e.preventDefault()
          this.navigateToNextPage(currentConfig)
          break

        case 'PageUp':
          e.preventDefault()
          this.navigateToPreviousPage(currentConfig)
          break

        case 'PageDown':
          e.preventDefault()
          this.navigateToNextPage(currentConfig)
          break
      }
    })
  }

  getGreasyForkKeyConfig(): KeyboardPaginationConfig {
    return {
      container: GREASY_FORK_PAGINATION_CONFIG.selector.container,
      itemSelector: GREASY_FORK_PAGINATION_CONFIG.childSelector.allPage,
      selectedSelector: GREASY_FORK_PAGINATION_CONFIG.childSelector.currentPage,
    }
  }

  getGiteeKeyConfig(): KeyboardPaginationConfig {
    return {
      container: GITEE_PAGINATION_CONFIG.selector.container,
      itemSelector: GITEE_PAGINATION_CONFIG.childSelector.allPage,
      selectedSelector: GITEE_PAGINATION_CONFIG.childSelector.currentPage,
    }
  }

  getGithubKeyConfig(): KeyboardPaginationConfig {
    const config = GITHUB_PAGE_PAGINATION_CONFIG[this.currentPageType as GithubPageType]
    const { selector, childSelector } = config || {}

    return {
      container: selector?.container || '',
      itemSelector: childSelector?.allPage || '',
      selectedSelector: childSelector?.currentPage || '',
    }
  }

  /**
   * 导航到上一页
   * @private
   */
  private navigateToPreviousPage(config: KeyboardPaginationConfig): void {
    // 上一页按钮
    const $prevPageBtn = $(`${config.container} ${config.itemSelector}`).filter((_, el) =>
      ToolKit.string.includesText($(el), '上一页', 'Previous'),
    )

    if ($prevPageBtn && $prevPageBtn.length > 0) {
      $prevPageBtn[0]?.click()
      return
    }

    // 页码
    const $currentPage = $(`${config.container} ${config.selectedSelector}`) // 当前选中页码
    const $prevLink = $currentPage.prev(config.itemSelector) // 上一个页码链接

    if ($prevLink && $prevLink.length > 0) {
      const href = $prevLink.attr('href') || ''

      if (ToolKit.browser.url.isValidHref(href)) {
        ToolKit.browser.url.openTab(href)
      }
      else {
        ToolKit.dom.handleJavascriptLink($prevLink)
      }
    }
  }

  /**
   * 导航到下一页
   * @private
   */
  private navigateToNextPage(config: KeyboardPaginationConfig): void {
    // 下一页按钮
    const $nextPageBtn = $(`${config.container} ${config.itemSelector}`).filter((_, el) =>
      ToolKit.string.includesText($(el), '下一页', 'Next'),
    )

    if ($nextPageBtn && $nextPageBtn.length > 0) {
      $nextPageBtn[0]?.click()
      return
    }

    // 页码
    const $currentPage = $(`${config.container} ${config.selectedSelector}`) // 当前选中页码
    const $nextLink = $currentPage.next(config.itemSelector) // 下一个页码链接

    if ($nextLink && $nextLink.length > 0) {
      const href = $nextLink.attr('href') || ''

      if (ToolKit.browser.url.isValidHref(href)) {
        ToolKit.browser.url.openTab(href)
      }
      else {
        ToolKit.dom.handleJavascriptLink($nextLink)
      }
    }
  }

  applyConfig(config: Partial<Config>): void {
    super.updateConfig(config)

    this.handlePagination()

    logger.info(`[${this.name}] Config updated and apply`, this.config)
  }

  getStyles(): string {
    return ``
  }
}
